﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Web.Routing;

namespace DNA.Mvc
{
    /// <summary>
    /// Provides the file sharing service of the portal.It implement the IFileSharingService access 
    /// Server File System service.
    /// </summary>
    public class FileWebResourceService : IWebResourceService
    {
        private Route Route
        {
            get
            {
                return (Route)RouteTable.Routes["dna_webfiles_get"];
            }
        }

        /// <summary>
        /// Returns the physical file path that corresponds to the specified the resoure url on the Web server.
        /// </summary>
        /// <param name="url">The resoure url.</param>
        /// <returns> The physical file path that corresponds to path.</returns>
        public string MapPath(Uri url)
        {
            var routeData = Route.GetRouteData(UrlUtility.CreateRequestContext(url).HttpContext);
            string website = routeData.Values["website"] as string;
            string path = routeData.Values["path"] as string;
            string webPath = website.Equals("home", StringComparison.OrdinalIgnoreCase) ? "~/shared/public" : "~/shared/personal/" + website;
            return HttpContext.Current.Server.MapPath(webPath + "/" + path);
        }

        /// <summary>
        /// Deletes the specified file. 
        /// </summary>
        /// <param name="url">Specified the resource uri to delete.</param>
        public void Delete(Uri url)
        {
            string fn = MapPath(url);

            if (!string.IsNullOrEmpty(Path.GetExtension(fn)))
            {
                if (File.Exists(fn))
                    File.Delete(fn);
            }
            else
            {
                if (Directory.Exists(fn))
                    Directory.Delete(fn, true);
            }
        }

        /// <summary>
        /// Create the parth for specified uri.
        /// </summary>
        /// <param name="url">The directory path to create.</param>
        public void CreatePath(Uri url)
        {
            string fn = MapPath(url);
            DirectoryInfo dir = Directory.CreateDirectory(fn);
        }

        /// <summary>
        ///  Save the data to destaintion path.
        /// </summary>
        /// <param name="data">The raw data of file.</param>
        /// <param name="fileName">Specified the file name.</param>
        /// <param name="destURI">the specified destaintion path where to save.</param>
        public Uri SaveFile(byte[] data, string fileName, Uri destURI)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            if (string.IsNullOrEmpty(fileName))
                throw new ArgumentNullException("fileName");

            if (destURI == null)
                throw new ArgumentNullException("destURI");

            string dest = MapPath(destURI);
            string _fileName = fileName;
            if (fileName.IndexOf("/") > 0)
                _fileName = _fileName.Replace("/", "_");
            var _target = "";

            if (!Directory.Exists(dest))
                Directory.CreateDirectory(dest);

            if (dest.EndsWith("\\"))
                _target = dest + _fileName;
            else
                _target = dest + "\\" + fileName;

            File.WriteAllBytes(_target, data);

            var _newURI = "";
            if (destURI.ToString().EndsWith("/"))
                _newURI = destURI.ToString() + _fileName;
            else
                _newURI = destURI.ToString() + "/" + _fileName;
            return new Uri(_newURI);
        }

        /// <summary>
        ///  Move a file or a directory and its contents to a new location.
        /// </summary>
        /// <param name="sourceUrl"> The url of the file or directory to move.</param>
        /// <param name="destUrl">The destination url to the new location for sourceURI</param>
        public void Move(Uri sourceUrl, Uri destUrl)
        {
            string src = MapPath(sourceUrl);
            string dest = MapPath(destUrl);
            Directory.Move(src, dest);
        }

        /// <summary>
        /// Get the file's raw data for specified filename
        /// </summary>
        /// <param name="url">The uri of the resource file</param>
        /// <returns>A byte array contains the file raw data.</returns>
        public byte[] Open(Uri url)
        {
            string file = MapPath(url);
            if (File.Exists(file))
                return File.ReadAllBytes(file);
            return null;
        }

        /// <summary>
        /// Gets the file info objects by the specified path.
        /// </summary>
        /// <param name="url">The specified path</param>
        /// <returns>A collection contains resource uri.</returns>
        public IEnumerable<Uri> GetFiles(Uri url)
        {
            string _path = MapPath(url);
            if (!Directory.Exists(_path))
                return null;

            string[] files = Directory.GetFiles(_path);
            List<Uri> fileUrls = new List<Uri>();

            foreach (string file in files)
            {
                DirectoryInfo info = new DirectoryInfo(file);
                string _url = url.ToString().EndsWith("/") ? url.ToString() + info.Name : url.ToString() + "/" + info.Name;
                Uri _uri = null;
                Uri.TryCreate(_url, UriKind.RelativeOrAbsolute, out _uri);
                if (_uri != null)
                    fileUrls.Add(_uri);
            }

            return fileUrls;
        }

        /// <summary>
        ///  Gets the sub path uris by the specified path.
        /// </summary>
        /// <param name="url">The specified path.</param>
        /// <returns>A collection contains resource path uri.</returns>
        public IEnumerable<Uri> GetPaths(Uri url)
        {
            string _path = MapPath(url);
            string[] dirs = Directory.GetDirectories(_path);
            List<Uri> dirUrls = new List<Uri>();

            foreach (string dir in dirs)
            {
                DirectoryInfo info = new DirectoryInfo(dir);
                string _url = url.ToString().EndsWith("/") ? url.ToString() + info.Name : url.ToString() + "/" + info.Name;
                dirUrls.Add(new Uri(_url));
            }
            return dirUrls;
        }

    }
}
